package com.hpe.core.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.NullArgumentException;
import org.apache.commons.lang.StringUtils;

import com.hpe.core.enums.ReportGroupEnum;

/**
 * 日期工具类 默认使用 "yyyy-MM-dd HH:mm:ss" 格式化日期
 * 
 */
public final class DateUtils {
    /**
     * 英文简写（默认）如：2010-12
     */
    public static String       FORMAT_MONTH        = "yyyy-MM";
    /**
     * 英文简写（默认）如：2010-12-01
     */
    public static String       FORMAT_SHORT        = "yyyy-MM-dd";
    /**
     * 英文简写（默认）如：2010-12-01 09
     */
    public static String       FORMAT_HOUR         = "yyyy-MM-dd HH";

    /**
     * 英文全称 如：2010-12-01 23:15:06
     */
    public static String       FORMAT_LONG         = "yyyy-MM-dd HH:mm:ss";
    /**
     * 精确到毫秒的完整时间 如：yyyy-MM-dd HH:mm:ss.S
     */
    public static String       FORMAT_FULL         = "yyyy-MM-dd HH:mm:ss.S";
    /**
     * 中文简写 如：2010年12月01日
     */
    public static String       FORMAT_SHORT_CN     = "yyyy年MM月dd";
    /**
     * 用作文件名的格式：20101201
     */
    public static String       FORMAT_SHORT_FOLDER = "yyyyMMdd";
    /**
     * 中文全称 如：2010年12月01日 23时15分06秒
     */
    public static String       FORMAT_LONG_CN      = "yyyy年MM月dd日  HH时mm分ss秒";
    /**
     * 精确到毫秒的完整中文时间
     */
    public static String       FORMAT_FULL_CN      = "yyyy年MM月dd日  HH时mm分ss秒SSS毫秒";
    /** 周一 */
    public static final String MONDAY              = "Monday";
    /** 周日 */
    public static final String SUNDAY              = "Sunday";
    /** 日期切片类型 */
    public static final String DATE_POINT_TYPE     = "datePointType";
    /** 日期切片结果 */
    public static final String DATE_POINT_RESULT   = "results";

    /**
     * 获得默认的 date pattern
     */
    public static String getDatePattern() {
        return FORMAT_LONG;
    }

    /**
     * 根据预设格式返回当前日期
     * 
     * @return
     */
    public static String getNow() {
        return format(new Date());
    }

    /**
     * 根据用户格式返回当前日期
     * 
     * @param format
     * @return
     */
    public static String getNow(String format) {
        return format(new Date(), format);
    }

    /**
     * 使用预设格式格式化日期
     * 
     * @param date
     * @return
     */
    public static String format(Date date) {
        return format(date, getDatePattern());
    }

    /**
     * 使用用户格式格式化日期
     * 
     * @param date
     *            日期
     * @param pattern
     *            日期格式
     * @return
     */
    public static String format(Date date, String pattern) {
        String returnValue = "";
        if (date != null) {
            SimpleDateFormat df = new SimpleDateFormat(pattern);
            returnValue = df.format(date);
        }
        return (returnValue);
    }

    /**
     * 给没有小时分钟的日期添加最大的时间
     * 
     * @param ymdStr yyyy-MM-dd
     *            
     * @return Date
     */
    public static Date parseAddMaxTime(String ymdStr) {
        return parse(ymdStr + " 23:59:59", getDatePattern());
    }

    /**
     * 使用预设格式提取字符串日期
     * 
     * @param strDate
     *            日期字符串
     * @return
     */
    public static Date parse(String strDate) {
        return parse(strDate, getDatePattern());
    }

    /**
     * 使用用户格式提取字符串日期
     * 
     * @param strDate
     *            日期字符串
     * @param pattern
     *            日期格式
     * @return
     */
    public static Date parse(String strDate, String pattern) {
        SimpleDateFormat df = new SimpleDateFormat(pattern);
        try {
            return df.parse(strDate);
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 在日期上增加数个整月
     * 
     * @param date
     *            日期
     * @param n
     *            要增加的月数
     * @return
     */
    public static Date addMonth(Date date, int n) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, n);
        return cal.getTime();
    }

    /**
     * 在日期上增加天数
     * 
     * @param date
     *            日期
     * @param n
     *            要增加的天数
     * @return
     */
    public static Date addDay(Date date, int n) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, n);
        return cal.getTime();
    }

    /**
     * 在日期上增加小时
     * @param date 源日期
     * @param n 要增加的小时数
     * @return 增加小时候的日期
     */
    public static Date addHour(Date date, int n) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.HOUR, n);
        return cal.getTime();
    }

    /**
     * 获取时间戳
     */
    public static String getTimeString() {
        SimpleDateFormat df = new SimpleDateFormat(FORMAT_FULL);
        Calendar calendar = Calendar.getInstance();
        return df.format(calendar.getTime());
    }

    /**
     * 获取日期年份
     * 
     * @param date
     *            日期
     * @return
     */
    public static String getYear(Date date) {
        return format(date).substring(0, 4);
    }

    /**
     * 按默认格式的字符串距离今天的天数
     * 
     * @param date
     *            日期字符串
     * @return
     */
    public static int countDays(String date) {
        long t = Calendar.getInstance().getTime().getTime();
        Calendar c = Calendar.getInstance();
        c.setTime(parse(date));
        long t1 = c.getTime().getTime();
        return (int) (t / 1000 - t1 / 1000) / 3600 / 24;
    }

    /**
     * 按用户格式字符串距离今天的天数
     * 
     * @param date
     *            日期字符串
     * @param format
     *            日期格式
     * @return
     */
    public static int countDays(String date, String format) {
        long t = Calendar.getInstance().getTime().getTime();
        Calendar c = Calendar.getInstance();
        c.setTime(parse(date, format));
        long t1 = c.getTime().getTime();
        return (int) (t / 1000 - t1 / 1000) / 3600 / 24;
    }

    /**
     * 计算两个日期间隔的月数
     * @param date1 <String>
     * @param date2 <String>
     * @return int
     * @throws ParseException
     */
    public static int getMonthSpace(String dateBegin, String dateEnd) throws ParseException {

        int result = 0;

        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();

        c1.setTime(parse(dateBegin, FORMAT_SHORT));
        c2.setTime(parse(dateEnd, FORMAT_SHORT));
        
        int year1 = c1.get(Calendar.YEAR);
        int year2 = c2.get(Calendar.YEAR);

        result = (year2 * 12 + c2.get(Calendar.MONDAY)) - (year1 * 12 + c1.get(Calendar.MONDAY));
        return Math.abs(result);
    }

    /**
     * 判断给定时间是否已经超过当前时间
     * @param overdueDate 要判定的时间
     * @return true:如果超过当前时间
     */
    public static boolean isOverdue(Date overdueDate) {
        return overdueDate.getTime() - System.currentTimeMillis() < 0;
    }

    /**
     * 处理统计时间，根据起止日期的差值，将时间单位划分为小时、天、周、月
     * @param dateBeginStr 起始日期字符串
     * @param dateEndStr 结束日期字符串
     * @return 划分好的日期节点集合
     */
    public static String getGroupByCondition(String dateBeginStr, String dateEndStr) {
        Date dateBegin = parse(dateBeginStr, FORMAT_SHORT);
        Date dateEnd = parse(dateEndStr, FORMAT_SHORT);
        // 一天24小时的毫秒数
        long dayMillisecond = 24 * 60 * 60 * 1000;
        // 起止日期的毫秒差值
        long diffMillisecond = dateEnd.getTime() - dateBegin.getTime() + dayMillisecond;
        long diffDays = diffMillisecond / dayMillisecond;
        long diffMonth = 0;
        try {
            diffMonth = getMonthSpace(dateBeginStr, dateEndStr);
        } catch (ParseException e) {
            throw new RuntimeException("计算相差月数失败");
        }
        if (diffDays == 1) {
            return ReportGroupEnum.GROUP_BY_HOUR.getCode();
        } else if (diffDays > 1 && diffMonth < 2) {
            // 相差日期不足2月，按天划分
            return ReportGroupEnum.GROUP_BY_DAY.getCode();
        } else {
            // 超过30天，按月划分
            return ReportGroupEnum.GROUP_BY_MONTH.getCode();
        }
    }

    /**
     * 时间切片，根据传入的起止日期的间隔满足的条件，对时间进行切片
     * @param dateBeginStr 起始日期
     * @param dateEndStr 结束日期
     * @return 切片倒序集合
     * @throws Exception
     */
    public static List<String> getDatePoint(String dateBeginStr, String dateEndStr) throws Exception {
        Date dateBegin = parse(dateBeginStr, FORMAT_SHORT);
        Date dateEnd = parse(dateEndStr, FORMAT_SHORT);
        // 一天24小时的毫秒数
        long dayMillisecond = 24 * 60 * 60 * 1000;
        // 起止日期的毫秒差值
        long diffMillisecond = dateEnd.getTime() - dateBegin.getTime() + dayMillisecond;
        // 两个日期相差的天数
        long diffDays = diffMillisecond / dayMillisecond;
        // 两个日期相差的月数
        int diffMonths = getMonthSpace(dateBeginStr, dateEndStr);
        if (diffDays < 1) {
            throw new IllegalArgumentException("起始日期大于结束日期");
        }
        List<String> results = new ArrayList<String>();
        Date newBeginDate = null;
        if (diffDays == 1) {
            // 日期间隔一天（当天）
            newBeginDate = parse(dateBeginStr + " 00", FORMAT_HOUR);
            results.add(format(newBeginDate, FORMAT_HOUR));
            for (int i = 1; i < 24; i++) {
                results.add(format(addHour(newBeginDate, i), FORMAT_HOUR));
            }
        } else if (diffDays > 1 && diffMonths < 2) {
            // 不足一月
            newBeginDate = parse(dateBeginStr, FORMAT_SHORT);
            results.add(format(newBeginDate, FORMAT_SHORT));
            for (int i = 1; i < diffDays; i++) {
                results.add(format(addDay(newBeginDate, i), FORMAT_SHORT));
            }
        } else {
            // 月份大于1
            newBeginDate = parse(dateBeginStr, FORMAT_MONTH);
            results.add(format(newBeginDate, FORMAT_MONTH));
            for (int i = 1; i <= diffMonths; i++) {
                results.add(format(addMonth(newBeginDate, i), FORMAT_MONTH));
            }
        }
        // 倒序
        Collections.reverse(results);
        return results;
    }

    /**
     * 时间切片，根据传入的起止日期的间隔满足的条件，对时间进行切片
     * @param dateBeginStr 起始日期
     * @param dateEndStr 结束日期
     * @return 切片倒序集合:DATE_POINT_TYPE(时间切片类型)，DATE_POINT_RESULT（切片后的数据节点集合）
     *          当DATE_POINT_TYPE = ReportGroupEnum.GROUP_BY_WEEK.getCode()时，结果集中的数据格式为"周起始日期.周结束日期"，如2015-08-24.2015-08-30
     * @throws Exception
     */
    public static Map<String, Object> getDatePointInludeWeek(String dateBeginStr, String dateEndStr) throws Exception {
        Date dateBegin = parse(dateBeginStr, FORMAT_SHORT);
        Date dateEnd = parse(dateEndStr, FORMAT_SHORT);
        // 一天24小时的毫秒数
        long dayMillisecond = 24 * 60 * 60 * 1000;
        // 起止日期的毫秒差值
        long diffMillisecond = dateEnd.getTime() - dateBegin.getTime() + dayMillisecond;
        // 两个日期相差的天数
        long diffDays = diffMillisecond / dayMillisecond;
        // 两个日期相差的月数
        int diffMonths = getMonthSpace(dateBeginStr, dateEndStr);
        if (diffDays < 1) {
            throw new IllegalArgumentException("起始日期大于结束日期");
        }

        Map<String, Object> resultMap = new HashMap<String, Object>();
        List<String> results = new ArrayList<String>();
        String datePointType = null;
        if (diffDays >= 1 && diffDays <= 7) {
            datePointType = ReportGroupEnum.GROUP_BY_DAY.getCode();
            // 按天划分
            results.add(format(dateBegin, FORMAT_SHORT));
            for (int i = 1; i < diffDays; i++) {
                results.add(format(addDay(dateBegin, i), FORMAT_SHORT));
            }
        } else if (diffDays > 7 && diffDays <= 31) {
            datePointType = ReportGroupEnum.GROUP_BY_WEEK.getCode();
            results = weekPointHandler(dateBegin, dateEnd);
        } else {
            // 按满月划分
            datePointType = ReportGroupEnum.GROUP_BY_MONTH.getCode();
            dateBegin = parse(dateBeginStr, FORMAT_MONTH);
            results.add(format(dateBegin, FORMAT_MONTH));
            for (int i = 1; i <= diffMonths; i++) {
                results.add(format(addMonth(dateBegin, i), FORMAT_MONTH));
            }
        }
        // 倒序
        Collections.reverse(results);
        resultMap.put(DATE_POINT_RESULT, results);
        resultMap.put(DATE_POINT_TYPE, datePointType);
        return resultMap;
    }

    /**
     * @param dateBegin 起始日期
     * @param dateEnd 结束日期
     */
    private static List<String> weekPointHandler(Date dateBegin, Date dateEnd) {
        List<String> results = new ArrayList<String>();
        // 按满周划分
        Map<String, Date> map = getFirstDateOfWeekZH(dateBegin);
        results.add(format(map.get(MONDAY), FORMAT_SHORT) + "." + format(map.get(SUNDAY), FORMAT_SHORT));
        while (true) {
            dateBegin = addDay(dateBegin, 7);
            map = getFirstDateOfWeekZH(dateBegin);
            if (!compareDate(map.get(MONDAY), dateEnd)) {
                break;
            }
            results.add(format(map.get(MONDAY), FORMAT_SHORT) + "." + format(map.get(SUNDAY), FORMAT_SHORT));
        }
        return results;
    }

    /**
     * 起止日期大小比较
     * @param smallerDate 较小的日期
     * @param biggerDate 较大的日期
     * @return true : 起始日期小于结束日期
     */
    public static boolean compareDate(String smallerDate, String biggerDate) {
        return compareDate(smallerDate, biggerDate, FORMAT_SHORT);
    }

    /**
     * 起止日期大小比较
     * @param smallerDate 较小的日期
     * @param biggerDate 较大的日期
     * @param format 日期格式
     * @return true : 起始日期小于结束日期
     */
    public static boolean compareDate(String smallerDate, String biggerDate, String format) {
        if (StringUtils.isBlank(smallerDate)) {
            throw new NullArgumentException("smallerDate");
        }
        if (StringUtils.isBlank(biggerDate)) {
            throw new NullArgumentException("biggerDate");
        }
        if (StringUtils.isBlank(format)) {
            throw new NullArgumentException("format");
        }

        Date samll = parse(smallerDate, format);
        Date big = parse(biggerDate, format);

        return samll.getTime() <= big.getTime();
    }

    /**
     * 起止日期大小比较
     * @param smallerDate 较小的日期
     * @param biggerDate 较大的日期
     * @return true : 起始日期小于结束日期
     */
    public static boolean compareDate(Date smallerDate, Date biggerDate) {
        return smallerDate.getTime() <= biggerDate.getTime();
    }

    /**
     * 通过给定日期，计算出该日期所处的起始日期和结束日期
     * @param dateStr 日期字符串
     * @return Map<String, Date> : Monday（key）=周一，Sunday（key）=周日
     */
    public static Map<String, Date> getFirstDateOfWeekZH(String dateStr) {

        Date date = parse(dateStr);
        Calendar cd = Calendar.getInstance();
        cd.setTime(date);
        // 获得今天是一周的第几天，星期一是第一天，星期二是第二天......  
        int dayOfWeek = cd.get(Calendar.DAY_OF_WEEK) - 2;
        // 先计算本周星期一的日期
        if (dayOfWeek == -1) {
            // 给定日期是周日
            cd.add(Calendar.DATE, -6);
        } else {
            cd.add(Calendar.DATE, -dayOfWeek);
        }

        Map<String, Date> resultMap = new HashMap<String, Date>();

        // 周一的日期
        resultMap.put(MONDAY, cd.getTime());
        // 计算本周日的日期
        cd.add(Calendar.DATE, 6);
        resultMap.put(SUNDAY, cd.getTime());

        return resultMap;
    }

    /**
     * 通过给定日期，计算出该日期所处的起始日期和结束日期
     * @param date 日期
     * @return Map<String, Date> : Monday（key）=周一，Sunday（key）=周日
     */
    public static Map<String, Date> getFirstDateOfWeekZH(Date date) {

        Calendar cd = Calendar.getInstance();
        cd.setTime(date);
        // 获得今天是一周的第几天，星期一是第一天，星期二是第二天......  
        int dayOfWeek = cd.get(Calendar.DAY_OF_WEEK) - 2;
        // 先计算本周星期一的日期
        if (dayOfWeek == -1) {
            // 给定日期是周日
            cd.add(Calendar.DATE, -6);
        } else {
            cd.add(Calendar.DATE, -dayOfWeek);
        }

        Map<String, Date> resultMap = new HashMap<String, Date>();
        // 周一的日期
        resultMap.put(MONDAY, parse(format(cd.getTime())));
        // 计算本周日的日期
        cd.add(Calendar.DATE, 6);
        resultMap.put(SUNDAY, parse(format(cd.getTime())));

        return resultMap;
    }

    /**
     * 判断当前日期是否为指定日期<br />
     * eg: isDayOf(1,1) 当天是否为周日<br>
     * eg: isDayOf(2,1) 当天是否为当月的第一天
     * @param type 类型，1周 /2月
     * @param day 当type周时 1 为周日，2为周一...7 为周六 ， 当type月时,1为1号，2为2号...
     */
    public static boolean isDayOf(int type, int day) {
        Calendar now = Calendar.getInstance();
        boolean res = false;
        if (type == 1) {
            int dayofweek = now.get(Calendar.DAY_OF_WEEK);
            if (dayofweek == day) {
                res = true;
            }
        } else if (type == 2) {
            int dayofmonth = now.get(Calendar.DAY_OF_MONTH);
            if (dayofmonth == day) {
                res = true;
            }
        }
        return res;
    }

    public static void main(String[] args) {
        Calendar now = Calendar.getInstance();
        System.out.println(now.get(Calendar.DAY_OF_WEEK));
    }
}